﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Input;
using DOMercury.Interfaces;
using DOMercury.Items;
using DOMercury.Engine;

namespace Bezel__
{
    #region State Enumerations
    public enum CurrentState
    {
        Items,
        Actions,
        Params
    }

    public enum ItemsMode
    {
        Selection,
        List,
        Text
    }

    #endregion

    public class DOMercuryCoreManager
    {
        private string input, paraminput;
        private IItem currentItem;
        private IItem currentParam;
        private IAction currentAction;
        private List<IItem> itemList;
        private List<IAction> actionList;
        private List<IItem> paramList;
        private System.Windows.Forms.Timer timer, ptimer;
        private int lastKeystrokeTime;
        private CurrentState currentState;
        private bool textmode = false;
        private bool ptextmode = false;
        private bool reset = true;
        private bool foundParamPaths = false;
        private bool foundItemPaths = false;
        private static DOMercuryCoreManager instance;
        private ItemList itemslist;
        private ItemList paramslist;
        private ActionList actionslist;
        
        private DOMercuryCoreManager()
        {
            instance = this;
            input = "";
            paraminput = "";
            currentParam = new DOMercury.Items.TextItem("");
            itemList = new List<IItem>();
            actionList = new List<IAction>();
            paramList = new List<IItem>();
            currentState = CurrentState.Items;
            timer = new System.Windows.Forms.Timer();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = 150;
            timer.Enabled = true;
            timer.Stop();
            ptimer = new System.Windows.Forms.Timer();
            ptimer.Tick += new EventHandler(ptimer_Tick);
            ptimer.Interval = 150;
            ptimer.Enabled = true;
            ptimer.Stop();

        }

        public void Initialize(ItemList IList, ActionList AList, ItemList PList)
        {
            itemslist = IList;
            actionslist = AList;
            paramslist = PList;
        }



        public static DOMercuryCoreManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new DOMercuryCoreManager();
                }
                return instance;
            }
   
        }

        #region Properties

        public bool FoundParamPaths
        {
            get
            {
                return foundParamPaths;
            }
            set
            {
                foundParamPaths = value;
            }
        }

        public bool FoundItemPaths
        {
            get
            {
                return foundItemPaths;
            }
            set
            {
                foundItemPaths = value;
            }
        }

        public CurrentState CurrentState
        {
            get
            {
                return currentState;
            }
            set
            {
                currentState = value;
                OnStateChanged(new object(), currentState);
                
            }
        }

        public IItem CurrentItem
        {
            get
            {
                return currentItem;
            }
            set
            {
                string oldtype = "";
                if (currentItem != null)
                {
                    oldtype = currentItem.ItemType;
                }
                currentItem = value;
                OnChangeCurrentItem(new object(), currentItem);
                if ((oldtype != currentItem.ItemType) || (actionList.Count == 0))
                {
                    GetNewActions();
                }                
            }
        }


        public IAction CurrentAction
        {
            get
            {
                return currentAction;
            }
            set
            {
                currentAction = value;
                OnChangeCurrentAction(new object(), currentAction);
                GetNewParams();
            }
        }

        public IItem CurrentParam
        {
            get
            {
                return currentParam;
            }
            set
            {
                currentParam = value;
                OnChangeCurrentParam(new object(), currentParam);
            }
        }

        public string ItemInput
        {
            get
            {
                return input;
            }
            set
            {
                input = value;
                OnInputChanged(new object(), input);
                if (!textmode)
                {
                    timer.Stop();
                    timer.Start();
                }
            }
        }

        public string ParamInput
        {
            get
            {
                return paraminput;
            }
            set
            {
                paraminput = value;
                OnParamInputChanged(new object(), paraminput);
                if (!ptextmode)
                {
                    ptimer.Stop();
                    ptimer.Start();
                }
            }
        }

        public string CurrentInput
        {
            get
            {
                switch (currentState)
                {
                    case CurrentState.Items:
                        return input; 
                    case CurrentState.Actions:
                        return "";  //TODO
                    default:
                        return paraminput;
                        
                }
            }
            set
            {
                switch (currentState)
                {
                    case CurrentState.Items:
                        ItemInput = value; break;
                    case CurrentState.Actions:
                        //TODO; 
                        break;
                    case CurrentState.Params:
                        ParamInput = value;
                        break;
                }
            }
        }

        public bool TextMode
        {
            get
            {
                return textmode;
            }
            set
            {
                textmode = value;
                OnTextModeToggled(new object(), textmode);
            }
        }

        #endregion

        public void DoKeyDown(object sender, KeyEventArgs e)
        {
            //get whether or not shift or control key is pressed
            bool shift = ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift);
            bool control = ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) == ModifierKeys.Control);
            e.Handled = true;
            switch (e.Key)
            {
                case Key.Tab:
                    if (shift)
                    {
                        ActivatePreviousPane();
                    }
                    else
                    {
                        ActivateNextPane();
                    }
                    
                    //Move to the next Pane
                    break;
                case Key.Enter:
                    //Perform Action
                    PerformAction();
                    
                    break;
                case Key.Escape:
                    //Hide Form
                    HideForm();
                    break;
                case Key.Down:
                    //Move down list of current listbox
                    IncrementCurrentList();
                    break;
                case Key.Up:
                    //Move up list of current listbox
                    DecrementCurrentList();
                    break;
                case Key.Right:
                    //Deep Dive
                    PushSubIndex(); break;
                case Key.Left:
                    //Return to Parent
                    PopSubIndex(); break;
                case Key.Delete:
                    //wipe out input
                    CurrentInput = ""; break;
                case Key.T:
                    if (control)
                    {
                        ToggleTextMode();
                    }
                    else
                    {
                        e.Handled = false;
                    }
                    break;
                case Key.V:
                    if (control)
                    {
                        SetInputFromClipboard();
                    }
                    else
                    {
                        e.Handled = false;
                    }
                    break;
                default:
                    //only handled if key combination found
                    e.Handled = false;
                    break;
            }

            //e.Handled = true;
            
        }

        public void SearchForFoundItems()
        {
            ItemsList items = DOMercury.Engine.Interface.EngineCore.GetSelectedItems();
            if (items != null)
            {
                if (items.Items.Count > 0)
                {
                    foundItemPaths = true;
                    CurrentItem = items;
                }
            }
        }

        public void DoTextInput(object sender, TextCompositionEventArgs e)
        {

            //Console.WriteLine(Environment.TickCount - lastKeystrokeTime);
			if (e.Text.Length == 0)
				return;

            char c = e.Text[0];
            //lastKeystrokeTime = Environment.TickCount;

            if (c == '\b') // if backspace
            {
                if (CurrentInput.Length > 0)
                {
                    //This should fire off search timer
                    CurrentInput = CurrentInput.Remove(CurrentInput.Length - 1, 1);
                    
                }
                else
                {
                    return;
                }
            }
            else
            {
                CurrentInput += c;
                
            }    
        }

        private void SetInputFromClipboard()
        {
            if (Clipboard.ContainsText())
            {
                CurrentInput = Clipboard.GetText();
            }
            else if (Clipboard.ContainsFileDropList())
            {
                if (currentState != CurrentState.Actions)
                {
                    List<DOMercury.Items.PathItem> pathItems = new List<PathItem>();
                    System.Collections.Specialized.StringCollection paths = Clipboard.GetFileDropList();
               
                    foreach (string path in paths)
                    {
                        pathItems.Add(new PathItem(path, System.IO.Path.GetFileName(path)));
                    }
                    DOMercury.Items.ItemsList pathsItem = new ItemsList(pathItems);
                    switch (currentState)
                    {
                        case CurrentState.Items:
                            foundItemPaths = true;
                            CurrentItem = pathsItem; break;
                        default:
                            foundParamPaths = true;
                            CurrentParam = pathsItem;
                        break;
                    }
                    
                }
            }
        }

        private void ToggleTextMode()
        {
            TextMode = !textmode;
        }

        private void ActivatePreviousPane()
        {
            switch (currentState)
            {
                case CurrentState.Items:
                    CurrentState = CurrentState.Params;
                    break;
                case CurrentState.Actions:
                    CurrentState = CurrentState.Items;
                    break;
                default:
                    CurrentState = CurrentState.Actions;
                    break;
            }
        }

        private void PopSubIndex()
        {
            string parentText;
            switch (currentState)
            {
                case CurrentState.Items:
                    parentText = DOMercury.Engine.Interface.EngineCore.ParentText;
                    DOMercury.Engine.Interface.EngineCore.PreviousIndex();
                    ItemInput = parentText;
                    break;
                case CurrentState.Params:
                    parentText = DOMercury.Engine.Interface.EngineCore.ParentParamText;
                    DOMercury.Engine.Interface.EngineCore.PreviousParamIndex();
                    ParamInput = parentText;
                    break;
                default:
                    break;
            }
        }

        private void PushSubIndex()
        {
            bool success;
            switch (currentState)
            {
                case CurrentState.Items:
                    success = DOMercury.Engine.Interface.EngineCore.SetSubIndex(currentItem, input, currentAction, currentParam);
                    if (success)
                    {
                        ItemInput = "";
                    }
                    break;
                case CurrentState.Params:
                    success = DOMercury.Engine.Interface.EngineCore.SetParamSubIndex(currentParam, paraminput, currentAction);
                    if (success)
                    {
                        ParamInput = "";
                    }
                    break;
                default:
                    break;
            }
            //return nruter;
        }

        private void HideForm()
        {
            OnHideForm(new object(), reset);
        }

        private void PerformAction()
        {
            if (currentAction != null)
            {
                reset = DOMercury.Engine.Interface.EngineCore.Perform(currentItem, currentAction, currentParam);
                HideForm();
            }
        }

        private void ActivateNextPane()
        {
            switch (currentState)
            {
                case CurrentState.Items:
                    CurrentState = CurrentState.Actions;
                    break;
                case CurrentState.Actions:
                    CurrentState = CurrentState.Params;
                    break;
                default:
                    CurrentState = CurrentState.Items;
                    break;
            }
        }

        void timer_Tick(object sender, EventArgs e)
        {
            timer.Stop();
            
           
            OnChangeItemList(new object(), Interface.EngineCore.GetItems(input));
            
        }

        private List<IItemWrapper> WrapItems(List<IItem> Items)
        {
            
            List<IItemWrapper> iiws = new List<IItemWrapper>();
            itemList = Items;
            switch (CurrentState)
            {
                case CurrentState.Items:
                    foundItemPaths = false;
                    CurrentItem = new IItemWrapper(Items[0]); break;
                case CurrentState.Params:
                    foundParamPaths = false;
                    CurrentParam = new IItemWrapper(Items[0]); break; break;
            }
           
            foreach (IItem i in Items)
            {
                IItemWrapper iw = new IItemWrapper(i);
                //iw.Icon = Interface.EngineCore.GetIconImageWPF(iw.DisplayDesc);
                iiws.Add(iw);

            }

            return iiws;
        }

        void ptimer_Tick(object sender, EventArgs e)
        {
            ptimer.Stop();
            
            
            OnChangeParamList(new object(), Interface.EngineCore.GetParamItems(paraminput));
            
        }


        private void GetNewActions()
        {
            Interface.EngineCore.GetActions(CurrentItem.ItemType, ref actionList);
            if (actionList != null)
            {
                if (actionList.Count > 0)
                {
                    CurrentAction = actionList[0];
                }
            }
            
            OnChangeActionList(new object(), actionList);
        }


        private void GetNewParams()
        {

            List<IItem> newParams = DOMercury.Engine.Interface.EngineCore.ChangeParametersAutoCompleteSource(currentAction.ParameterType, currentItem.ItemType);
  
            foundParamPaths = false;
            if (newParams != null)
            {
                if (newParams.Count > 0)
                {
                    CurrentParam = newParams[0];
                }
            }
            else
            {
                newParams = new List<IItem>();
            }
            

            OnChangeParamList(new object(), newParams);
        }

        private void IncrementCurrentList()
        {
            OnIncrementList(new object());
        }

        private void DecrementCurrentList()
        {
            OnDecrementList(new object());
        }


        #region Events

        public event ChangeIItemHandler OnChangeCurrentItem;

        public event ChangeIActionHandler OnChangeCurrentAction;

        public event ChangeIItemHandler OnChangeCurrentParam;

        public event ChangeIItemListHandler OnChangeItemList;

        public event ChangeIActionListHandler OnChangeActionList;

        public event ChangeIItemListHandler OnChangeParamList;

        public event InputChangedHandler OnInputChanged;

        public event InputChangedHandler OnParamInputChanged;

        public event StateChangedHandler OnStateChanged;

        public event TextModeToggledHandler OnTextModeToggled;

        public event HideFormHandler OnHideForm;

        public event GeneralEventHandler OnIncrementList;

        public event GeneralEventHandler OnDecrementList;

        #endregion
    }

    public delegate void ChangeIItemHandler(object sender, IItem Item);

    public delegate void ChangeIActionHandler(object sender, IAction Action);

    public delegate void ChangeIItemListHandler(object sender, List<IItem> Items);

    public delegate void ChangeIActionListHandler(object sender, List<IAction> Actions);

    public delegate void InputChangedHandler(object sender, string newInput);

    public delegate void StateChangedHandler(object sender, CurrentState newState);

    public delegate void TextModeToggledHandler(object sender, bool textMode);

    public delegate void HideFormHandler(object sender, bool reset);

    public delegate void GeneralEventHandler(object sender);

}
